﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows.Threading;
using TechnicalIndicators.Points;
using Visiblox.Charts;

namespace StockAnalyst2.Chart
{
	internal class BarModelToVisibloxConverter : IDisposable
	{
		#region Attributes

		private readonly ObservableCollection<Bar> _source;
		private readonly DataSeries<DateTime, decimal> _destination;
		private readonly Dispatcher _dispatcher;

		#endregion

		#region Public Methods

		public BarModelToVisibloxConverter(ObservableCollection<Bar> source, DataSeries<DateTime, decimal> destination, Dispatcher dispatcher)
		{
			_source = source;
			_destination = destination;
			_dispatcher = dispatcher;

			_source.CollectionChanged += this.Source_CollectionChanged; // Disposed
		}

		#endregion

		#region Event Handlers

		private void Source_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
		{
			if (_dispatcher.CheckAccess())
			{
				if (e.Action == NotifyCollectionChangedAction.Add)
				{
					List<DataPoint<DateTime, decimal>> tempPoints = new List<DataPoint<DateTime, decimal>>();

					foreach (Bar newItem in e.NewItems)
					{
						Dictionary<object, decimal> data = new Dictionary<object, decimal>();
						data.Add(Visiblox.Charts.CandlestickSeries.Open, newItem.Open);
						data.Add(Visiblox.Charts.CandlestickSeries.Close, newItem.Close);
						data.Add(Visiblox.Charts.CandlestickSeries.High, newItem.Maximum);
						data.Add(Visiblox.Charts.CandlestickSeries.Low, newItem.Minimum);

						tempPoints.Add(new MultiValuedDataPoint<DateTime, decimal>(newItem.Start, data));
					}

					_destination.AddRange(tempPoints);
				}
				else if (e.Action == NotifyCollectionChangedAction.Reset)
				{
					_destination.Clear();
				}
			}
			else
			{
				_dispatcher.BeginInvoke(new Action<object, NotifyCollectionChangedEventArgs>(this.Source_CollectionChanged), new object[] { sender, e });
			}
		}

		#endregion

		#region IDisposable

		protected bool Disposed { get; private set; }

		private void Dispose(bool disposing)
		{
			if (!this.Disposed)
			{
				this.InternalDispose(disposing);
			}

			this.Disposed = true;
		}

		protected virtual void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				_source.CollectionChanged -= this.Source_CollectionChanged;
			}

			// Dispose here only unmanaged objects 
			// Don’t use managed objects here because maybe 
			// they have been finalized already
		}

		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		~BarModelToVisibloxConverter()
		{
			this.Dispose(false);
		}

		#endregion
	}
}
